home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d12 / v8n13.arc / CONVERT.ASM < prev    next >
Assembly Source File  |  1989-06-10  |  22KB  |  427 lines

  1. ;------------------------------------------------------;
  2. ;  Convert.com - Converts either a number or character ;
  3. ;  to complementary radices.                           ;
  4. ;  Decimal, Hexadecimal, Octal and Binary supported.   ;
  5. ;  PC Magazine * Michael J. Mefford                    ;
  6. ;------------------------------------------------------;
  7. _TEXT          SEGMENT PUBLIC 'CODE'
  8.                ASSUME  CS:_TEXT,DS:_TEXT,ES:_TEXT,SS:_TEXT
  9.                ORG     100H
  10. START:         JMP     MAIN
  11.  
  12. ;              DATA AREA
  13. ;              ---------
  14. SYNTAX         DB      CR,SPACE,SPACE,SPACE,CR,LF
  15. COPYRIGHT      DB      "CONVERT 1.0 (C) 1989 Ziff Communications Co.",CR,LF
  16. PROGRAMMER     DB      "PC Magazine ",BOX," Michael J. Mefford",CR,LF,LF
  17.  
  18.                DB      "Syntax:  CONVERT number[-number][radix] | "
  19.                DB      QUOTES,"character(s)",QUOTES,CR,LF
  20.                DB      "radix:  b = binary, h = hexadecimal, o = octal",CR,LF
  21.                DB      "default is decimal",LF,"$",CTRL_Z
  22.  
  23. CR             EQU     13
  24. LF             EQU     10
  25. CTRL_Z         EQU     26
  26. SPACE          EQU     32
  27. QUOTES         EQU     34
  28. BOX            EQU     254
  29. SPACE_CNT      EQU     5
  30.  
  31. INVALID_MSG    DB      "Invalid parameter",CR,LF
  32.                DB      "number range: 0 - 65535",CR,LF,"$"
  33.  
  34. RADIX_TYPE     DB      "HOB"                   ;Hex, octal, binary.
  35. RADIX_CNT      EQU     $ - RADIX_TYPE
  36.  
  37. INPUT_CALLS    DW      DECIMAL_INPUT, HEX_INPUT, OCTAL_INPUT, BINARY_INPUT
  38. CALLS_END      EQU     $ - 2
  39.  
  40. ;              CODE AREA
  41. ;              ---------
  42.  
  43. ;------------------------------------------------------------------------;
  44. ; Capitalize the parameters so a single compare for radices can be done. ;
  45. ;------------------------------------------------------------------------;
  46. MAIN           PROC    NEAR
  47.                CLD                             ;All string moves forward.
  48.                CMP     BYTE PTR DS:[80H],0     ;Are there parameters?
  49.                JNZ     PARSE                   ;If yes, continue.
  50.                JMP     ERROR_EXIT              ;Else, exit with syntax message.
  51.  
  52. ;------------------------------------------------------------------------------;
  53. ; Parse the parameters by looking for either carriage return, quotes, or dash. ;
  54. ;------------------------------------------------------------------------------;
  55. PARSE:         MOV     DL,LF                   ;Print a linefeed just to first
  56.                CALL    PRINT_CHAR              ; to make our output look pretty.
  57.                MOV     SI,82H                  ;Point to parameters again.
  58. NEXT_INPUT:    MOV     BP,SI                   ;Start parameter start.
  59. NEXT_PARSE:    LODSB                           ;Get a byte.
  60.                CMP     AL,CR                   ;Is it carriage return?
  61.                JZ      EVALUATE                ;If yes, done here.
  62.                CMP     AL,QUOTES               ;Is it quotes?
  63.                JZ      CHARACTER               ;If yes, character entry.
  64.                CMP     AL,"-"                  ;Is it delimiting dash?
  65.                JNZ     NEXT_PARSE              ;If no, find parameter end.
  66.                CMP     BP,82H                  ;Else, is this first dash?
  67.                JNZ     EVALUATE                ;If no, evaluate just the two.
  68.                PUSH    SI                      ;Save our position.
  69.                CALL    GET_NUMBER              ;Get the parameter.
  70.                POP     SI                      ;Restore our position.
  71.                PUSH    BX                      ;Save the number.
  72.                JMP     SHORT NEXT_INPUT        ;Get second parameter.
  73.  
  74. ;----------------------------------------------------------------------;
  75. ; If quotes were detected, store up to two characters to be evaluated. ;
  76. ;----------------------------------------------------------------------;
  77. CHARACTER:     XOR     BX,BX                   ;Assume no characters.
  78.                LODSB                           ;Get a byte.
  79.                CMP     AL,CR                   ;End of parameter?
  80.                JZ      ERROR_EXIT              ;If yes, no character; exit.
  81.                MOV     BL,AL                   ;Else, store character.
  82.                LODSB                           ;Get next character.
  83.                CMP     AL,CR                   ;End of parameter?
  84.                JZ      GOT_CHAR                ;If yes, only one character.
  85.                CMP     AL,QUOTES               ;Is it quotes?
  86.                JNZ     GET_CHAR                ;If no, valid second character.
  87.                CMP     BYTE PTR [SI],QUOTES    ;Is it followed by quotes?
  88.                JNZ     GOT_CHAR                ;If no, not quotes in quotes.
  89. GET_CHAR:      MOV     BH,AL                   ;Else, store second character.
  90.                XCHG    BH,BL                   ;Swap so in right order.
  91. GOT_CHAR:      XOR     CX,CX                   ;Zero out parameter count.
  92.                JMP     SHORT CONVERT           ;Convert the character.
  93.  
  94. ;-------------------------------------------------------------;
  95. ; Find range of numbers and display the complementry radices. ;
  96. ;-------------------------------------------------------------;
  97. EVALUATE:      CALL    GET_NUMBER              ;Get the parameter.
  98.                XOR     CX,CX                   ;Assume only one parameter.
  99.                CMP     BP,82H                  ;Where there more than one?
  100.                JZ      CONVERT                 ;If no, convert just the one.
  101.                POP     CX                      ;Else, retrieve the first one.
  102.                CMP     CX,BX                   ;Is it the larger of the two?
  103.                JA      FIND_RANGE              ;If yes, find range.
  104.                XCHG    BX,CX                   ;Else, swap numbers.
  105. FIND_RANGE:    SUB     CX,BX                   ;Find difference.
  106.  
  107. CONVERT:       INC     CX                      ;Increment by one for "thru".
  108.                MOV     DI,BX                   ;Save number to be converted.
  109. OUTPUT:        PUSH    CX                      ;Save count to be converted.
  110.                CALL    DECIMAL_OUTPUT          ;Display decimal, hexadecimal,
  111.                CALL    SPACE_IT                ; octal and binary equivalents
  112.                CALL    HEX_OUTPUT              ; with spaces in between.
  113.                CALL    SPACING
  114.                CALL    OCTAL_OUTPUT
  115.                CALL    SPACING
  116.                CALL    BINARY_OUTPUT
  117.                CALL    SPACING
  118.                CALL    ASCII_OUTPUT
  119.                MOV     DL,CR
  120.                CALL    PRINT_CHAR
  121.                MOV     DL,LF
  122.                CALL    PRINT_CHAR
  123.                INC     DI                      ;Get ready for next number.
  124.                POP     CX                      ;Retrieve conversion count.
  125.                LOOP    OUTPUT                  ;Do them all.
  126.                XOR     AL,AL                   ;Exit with ErrorLevel of zero.
  127.                JMP     SHORT EXIT
  128.  
  129. ;---------------------------------------------------------------------------;
  130. ; Exit with syntax message and ErrorLevel of 1 if error, else ErrorLevel 0. ;
  131. ;---------------------------------------------------------------------------;
  132. ERROR_EXIT:    MOV     DX,OFFSET SYNTAX        ;Display syntax.
  133.                CALL    PRINT_STRING
  134.                MOV     AL,1                    ;ErrorLevel one.
  135. EXIT:          MOV     AH,4CH
  136.                INT     21H                     ;Terminate.
  137. MAIN           ENDP
  138.  
  139. ;              *************
  140. ;              *SUBROUTINES*
  141. ;              *************
  142.  
  143. ;------------------------------------------------------------------------------;
  144. ; INPUT:  SI points to byte after parameter end; BP points to parameter start. ;
  145. ; OUTPUT: BX = number.                                                         ;
  146. ; CALLS:  DECIMAL_INPUT, HEX_INPUT, OCTAL_INPUT, BINARY_INPUT.                 ;
  147. ;------------------------------------------------------------------------------;
  148. GET_NUMBER     PROC    NEAR
  149.                DEC     SI                      ;Adjust pointer to parameter end.
  150.                MOV     CX,SI                   ;Save SI.
  151.                MOV     SI,BP                   ;Point to parameter start.
  152. NEXT_CAP:      CMP     SI,CX                   ;Are we end of parameter?
  153.                JZ      STRING_LENGTH           ;If yes, done here.
  154.                LODSB                           ;Get a byte.
  155.                CMP     AL,"a"
  156.                JB      NEXT_CAP
  157.                CMP     AL,"z"
  158.                JA      NEXT_CAP
  159.                AND     BYTE PTR [SI-1],5FH     ;Capitalize.
  160.                JMP     SHORT NEXT_CAP
  161.  
  162. STRING_LENGTH: MOV     SI,BP                   ;Point to parameter start.
  163.                SUB     CX,BP                   ;Find parameter length.
  164.                PUSH    CX                      ;Save it.
  165.  
  166. NEXT_RADIX:    XCHG    CX,BX                   ;Save count in BX.
  167.                LODSB                           ;Get a byte.
  168.                MOV     CX,RADIX_CNT            ;Count of radix appendixes in CX.
  169.                MOV     DI,OFFSET RADIX_TYPE    ;Point to appendixes.
  170.                REPNZ   SCASB                   ;Is it an appendix?
  171.                JZ      INPUT                   ;If yes, evaluate.
  172.                XCHG    CX,BX                   ;Else, retrieve parameter count.
  173. LOOP_RADIX:    LOOP    NEXT_RADIX              ;Check next byte.
  174.                MOV     CX,RADIX_CNT            ;If no appendix, assume decimal.
  175.  
  176. INPUT:         SHL     CX,1                    ;Convert count to word pointer.
  177.                MOV     DI,OFFSET CALLS_END     ;Point to input calls end.
  178.                SUB     DI,CX                   ;Point to appropriate call.
  179.                POP     CX                      ;Retrieve parameter length.
  180.                MOV     SI,BP                   ;Point to parameter start.
  181.                XOR     BX,BX                   ;Start with a zero number.
  182.                CALL    [DI]                    ;Get the number.
  183.                MOV     DX,OFFSET INVALID_MSG   ;Print error message if
  184.                JNC     END_NUMBER              ; number invalid.
  185.                CALL    PRINT_STRING
  186.                JMP     SHORT ERROR_EXIT
  187. END_NUMBER:    RET                             ;Else, return with number in BX.
  188. GET_NUMBER     ENDP
  189.  
  190. ;----------------------------------------------------------------------;
  191. ; INPUT:  SI points to parameter start; CX = parameter length; BX = 0. ;
  192. ; OUTPUT: BX = number; CY = 0 if valid entry; CY = 1 if invalid entry. ;
  193. ;----------------------------------------------------------------------;
  194. DECIMAL_INPUT  PROC    NEAR
  195. NEXT_DECIMAL:  LODSB                           ;Get a character.
  196.                SUB     AL,"0"                  ;ASCII to binary.
  197.                JC      LOOP_DECIMAL            ;If not between 0 and 9, skip.
  198.                CMP     AL,9
  199.                JA      LOOP_DECIMAL
  200.                CBW                             ;Convert to word.
  201.                XCHG    AX,BX                   ;Swap old and new number.
  202.                PUSH    CX                      ;Preserve counter.
  203.                MOV     CX,10                   ;Shift to left by multiplying
  204.                MUL     CX                      ; last entry by ten.
  205.                POP     CX                      ;Retrieve counter.
  206.                JC      END_DECIMAL             ;If carry, too big.
  207.                ADD     BX,AX                   ;Add new number and store in BX.
  208.                JC      END_DECIMAL             ;If carry, too big.
  209. LOOP_DECIMAL:  LOOP    NEXT_DECIMAL
  210.                CLC
  211. END_DECIMAL:   RET
  212. DECIMAL_INPUT  ENDP
  213.  
  214. ;-----------------------------------------------------------------------;
  215. ; INPUT  : SI points to parameter start; CX = parameter length; BX = 0. ;
  216. ; OUTPUT : BX = number; CY = 0 if valid entry; CY = 1 if invalid entry. ;
  217. ;-----------------------------------------------------------------------;
  218. BINARY_INPUT   PROC    NEAR
  219. NEXT_BIN:      LODSB                           ;Get a byte.
  220.                SUB     AL,"0"                  ;ASCII to binary.
  221.                JC      LOOP_BIN                ;If not 0 or 1, skip.
  222.                CMP     AL,1
  223.                JA      LOOP_BIN
  224.                SHL     BX,1                    ;Shift old number left one bit.
  225.                JC      END_BIN                 ;If carry, too big.
  226.                OR      BL,AL                   ;Else, add it to the number.
  227. LOOP_BIN:      LOOP    NEXT_BIN
  228.                CLC
  229. END_BIN:       RET
  230. BINARY_INPUT   ENDP
  231.  
  232. ;-----------------------------------------------------------------------;
  233. ; INPUT  : SI points to parameter start; CX = parameter length; BX = 0. ;
  234. ; OUTPUT : BX = number; CY = 0 if valid entry; CY = 1 if invalid entry. ;
  235. ;-----------------------------------------------------------------------;
  236. HEX_INPUT      PROC    NEAR
  237. NEXT_HEX:      LODSB                           ;Get a byte.
  238.                SUB     AL,"0"                  ;ASCII to binary.
  239.                JC      LOOP_HEX                ;If not 0 to 9, skip.
  240.                CMP     AL,9                    ;Is it A - F ?
  241.                JLE     NOT_ALPHA               ;If no, OK.
  242.                SUB     AL,7                    ;Else, adjust for alpha.
  243.                CMP     AL,10                   ;Is it punctuation?
  244.                JB      LOOP_HEX                ;If yes, skip.
  245.                CMP     AL,15                   ;Is it valid?
  246.                JA      LOOP_HEX                ;If no, skip.
  247. NOT_ALPHA:     TEST    BX,1111b SHL 12         ;Is the number going to overflow?
  248.                STC                             ;Assume yes.
  249.                JNZ     END_HEX                 ;If yes, too big.
  250.                PUSH    CX                      ;Else, preserve counter.
  251.                MOV     CL,4                    ;Shift old number four bits left.
  252.                SHL     BX,CL
  253.                POP     CX                      ;Retrieve counter.
  254.                OR      BL,AL                   ;Add to number.
  255. LOOP_HEX:      LOOP    NEXT_HEX
  256.                CLC
  257. END_HEX:       RET
  258. HEX_INPUT      ENDP
  259.  
  260. ;-----------------------------------------------------------------------;
  261. ; INPUT  : SI points to parameter start; CX = parameter length; BX = 0. ;
  262. ; OUTPUT : BX = number; CY = 0 if valid entry; CY = 1 if invalid entry. ;
  263. ;-----------------------------------------------------------------------;
  264. OCTAL_INPUT    PROC    NEAR
  265. NEXT_OCTAL:    LODSB                           ;Get a byte.
  266.                SUB     AL,"0"                  ;ASCII to binary.
  267.                JC      LOOP_OCTAL              ;If not 0 through 7, skip.
  268.                CMP     AL,7
  269.                JA      LOOP_OCTAL
  270.                TEST    BX,111b SHL 13          ;Is the number going to overflow?
  271.                STC                             ;Assume yes.
  272.                JNZ     END_OCTAL               ;If yes, too big.
  273.                PUSH    CX                      ;Else, save counter.
  274.                MOV     CL,3                    ;Shift old number left three bits
  275.                SHL     BX,CL
  276.                POP     CX                      ;Retrieve counter.
  277.                OR      BL,AL                   ;Add to number.
  278. LOOP_OCTAL:    LOOP    NEXT_OCTAL
  279.                CLC
  280. END_OCTAL:     RET
  281. OCTAL_INPUT    ENDP
  282.  
  283. ;-----------------------------------------------------------------------;
  284. ; INPUT  : SI points to parameter start; CX = parameter length; BX = 0. ;
  285. ; OUTPUT : BX = number; CY = 0 if valid entry; CY = 1 if invalid entry. ;
  286. ;-----------------------------------------------------------------------;
  287. DECIMAL_OUTPUT PROC    NEAR
  288.                MOV     AX,DI                   ;Retrieve number.
  289.                MOV     BX,10                   ;Divisor of ten.
  290.                XOR     CX,CX                   ;Zero in counter.
  291. NEXT_COUNT:    XOR     DX,DX                   ;Zero in high half.
  292.                DIV     BX                      ;Divide by ten.
  293.                ADD     DL,"0"                  ;Convert to ASCII.
  294.                PUSH    DX                      ;Save results.
  295.                INC     CX                      ;Also increment count.
  296.                CMP     AX,0                    ;Are we done?
  297.                JNZ     NEXT_COUNT              ;Continue until zero.
  298.                MOV     BX,CX                   ;Save the number of characters.
  299.  
  300. NEXT_NUMBER:   POP     DX                      ;Retrieve numbers.
  301.                CALL    PRINT_CHAR              ;And write them.
  302.                LOOP    NEXT_NUMBER
  303.                MOV     CX,SPACE_CNT + 5        ;Return with tab count.
  304.                SUB     CX,BX
  305.                RET
  306. DECIMAL_OUTPUT ENDP
  307.  
  308. ;----------------------------------------;
  309. ; INPUT: DI = number.                    ;
  310. ;----------------------------------------;
  311. HEX_OUTPUT     PROC    NEAR
  312.                MOV     BX,DI                   ;Retrieve number.
  313.                MOV     CX,404H                 ;4 positions/word; 4bits/char.
  314. ROTATE_HEX:    ROL     BX,CL                   ;Move highest bits to lowest.
  315.                MOV     DL,BL
  316.                AND     DL,1111B                ;Mask off all but four lowest.
  317.                ADD     DL,"0"                  ;Convert to ASCII.
  318.                CMP     DL,"9"                  ;Is it alpha.
  319.                JLE     PRINT_HEX               ;If no, print it.
  320.                ADD     DL,7                    ;Else, adjust.
  321. PRINT_HEX:     CALL    PRINT_CHAR              ;And write them.
  322.                DEC     CH                      ;Done all four positions?
  323.                JNZ     ROTATE_HEX              ;If no, get next.
  324.  
  325.                MOV     DL,"h"                  ;Tack on hex character.
  326.                CALL    PRINT_CHAR
  327.                RET
  328. HEX_OUTPUT     ENDP
  329.  
  330. ;----------------------------------------;
  331. ; INPUT: DI = number.                    ;
  332. ;----------------------------------------;
  333. OCTAL_OUTPUT   PROC    NEAR
  334.                MOV     BX,DI                   ;Retrieve number.
  335.                MOV     CX,603H                 ;6 positions/word; 3bits/char.
  336.                ROL     BX,1                    ;Special case first; get top bit.
  337.                MOV     DL,BL
  338.                AND     DL,1                    ;Mask off all but that bit.
  339.                JMP     SHORT OCTAL_ASCII       ;Write it.
  340.  
  341. OCTAL_ROTATE:  ROL     BX,CL                   ;Rotate highest 3 bits to lowest.
  342.                MOV     DL,BL
  343.                AND     DL,111B                 ;Mask off all but lowest 3 bits.
  344. OCTAL_ASCII:   ADD     DL,"0"                  ;Convert to ASCII.
  345.                CALL    PRINT_CHAR              ;Write it.
  346.                DEC     CH                      ;Do all 6 positions.
  347.                JNZ     OCTAL_ROTATE
  348.  
  349.                MOV     DL,"o"                  ;Tack on octal character.
  350.                CALL    PRINT_CHAR
  351.                RET
  352. OCTAL_OUTPUT   ENDP
  353.  
  354. ;----------------------------------------;
  355. ; INPUT: DI = number.                    ;
  356. ;----------------------------------------;
  357. BINARY_OUTPUT  PROC    NEAR
  358.                MOV     BX,DI                   ;Retrieve number.
  359.                MOV     CH,16                   ;Display all 16 positions.
  360. ROTATE_BIN:    ROL     BX,1                    ;Move highest bit to lowest.
  361.                MOV     DL,BL
  362.                AND     DL,1                    ;Mask off all but lowest.
  363.                ADD     DL,"0"                  ;Convert to ASCII.
  364.                CALL    PRINT_CHAR
  365.                CMP     CH,9                    ;Format with space between bytes.
  366.                JNZ     SKIP_SPACE
  367.                MOV     DL,SPACE
  368.                CALL    PRINT_CHAR
  369. SKIP_SPACE:    DEC     CH                      ;Do all 16 bits.
  370.                JNZ     ROTATE_BIN
  371.  
  372.                MOV     DL,"b"                  ;Tack on binary character.
  373.                CALL    PRINT_CHAR
  374.                RET
  375. BINARY_OUTPUT  ENDP
  376.  
  377. ;----------------------------------------;
  378. ; INPUT: DI = number.                    ;
  379. ;----------------------------------------;
  380. ASCII_OUTPUT   PROC    NEAR
  381.                XOR     BH,BH                   ;Page zero.
  382.                MOV     AX,0E22H                ;Write TTY a quote mark.
  383.                INT     10H                     ; via BIOS.
  384.  
  385.                MOV     CX,3                    ;Display 3 quotation marks and
  386.                MOV     AX,0A22H                ; do not update cursor position.
  387.                INT     10H
  388.                MOV     CX,2                    ;Display the low byte twice
  389.                MOV     AX,DI
  390.                MOV     AH,0AH                  ; at current cursor position.
  391.                INT     10H
  392.                MOV     CX,1                    ;Display the high byte once
  393.                MOV     AX,DI                   ; at current cursor position
  394.                XCHG    AL,AH
  395.                MOV     AH,0AH                  ; over the first low byte.
  396.                INT     10H
  397.                RET
  398. ASCII_OUTPUT   ENDP
  399.  
  400. ;---------------------------------------------------------------;
  401. ; These subroutines print and separate the display with spaces. ;
  402. ;---------------------------------------------------------------;
  403. PRINT_CHAR     PROC    NEAR
  404.                MOV     AH,2                    ;DOS display output.
  405.                INT     21H                     ;Character is in DL.
  406.                RET
  407. PRINT_CHAR     ENDP
  408.  
  409. ;-------------------------;
  410. PRINT_STRING   PROC    NEAR
  411.                MOV     AH,9                    ;DOS string output.
  412.                INT     21H                     ;DX points to string
  413.                RET                             ; terminated by "$".
  414. PRINT_STRING   ENDP
  415.  
  416. ;-------------------------;
  417. SPACING        PROC    NEAR
  418.                MOV     CX,SPACE_CNT            ;Retrieve space count between
  419. SPACE_IT:      MOV     DL,SPACE                ; outputs and print via DOS.
  420.                CALL    PRINT_CHAR
  421.                LOOP    SPACE_IT
  422.                RET
  423. SPACING        ENDP
  424.  
  425. _TEXT          ENDS
  426.                END     START
  427.